package main

import (
	"bytes"
	"fmt"
	"os"
	"path"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"text/template"
)

// 接口源目录
var (
	srcPath = "../include/"
)

func main() {
	switch os.Args[1] {
	case "c":
		genC()
	case "go":
		genGoDataType()
		genGoStruct()
		genGo()
	case "py":
		genPyDataType()
		genPyStruct()
		genPy()
	case "cs":
		genCsDataType()
		genCsStruct()
		genCs()
	}
	fmt.Println("finish.")
}

type fieldStruct struct {
	FieldType, FieldName, Comment string
}
type tplStruct struct {
	Comment, FuncTypeName, FuncName string
	FuncFields                      []fieldStruct
}

type dataTypeValue struct {
	Comment, Name, Value string
}
type dataType struct {
	Comment, Type, Name string
	Subs                []dataTypeValue
}

func tmpl(tplFileName string, content interface{}, funcMap template.FuncMap, outPath string) {
	_, curFile, _, _ := runtime.Caller(1)
	tplPath := filepath.Dir(curFile) // 模板文件与执行文件在同一目录

	fm := make(template.FuncMap, 0)
	fm["trimStar"] = func(str string) string {
		return strings.TrimPrefix(str, "*")
	}

	for k, v := range funcMap {
		fm[k] = v
	}

	t := template.New(path.Base(tplFileName)).Delims("[[", "]]").Funcs(fm)
	t, err := t.ParseFiles(path.Join(tplPath, tplFileName))
	if err != nil {
		panic(err)
	}
	var buf = bytes.Buffer{}
	err = t.Execute(&buf, content) // ***
	if err != nil {
		panic(err)
	}
	// 写入 .h
	err = os.WriteFile(path.Join(outPath, strings.TrimSuffix(tplFileName, filepath.Ext(tplFileName))), buf.Bytes(), os.ModePerm)
	if err != nil {
		panic(err)
	}
}

// generate 取接口中的函数,转换为对应的接口
func generate(tplExeFunc func(title string, on []*tplStruct, fn []*tplStruct)) {
	for _, hFileName := range []string{srcPath + "HSMdApi.h", srcPath + "HSTradeApi.h"} {
		var title string
		if strings.Contains(hFileName, "HSMdApi") {
			title = "quote"
		} else {
			title = "trade"
		}
		bsFile, err := os.ReadFile(hFileName)
		if err != nil {
			panic(err)
		}
		// 汉字处理
		// bsFile, _ = simplifiedchinese.GB18030.NewDecoder().Bytes(bsFile)
		/*
			///登录请求响应
			virtual void OnRspUserLogin(CHSRspUserLoginField *pRspUserLogin, CHSRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {};
		*/
		strFile := string(bsFile)
		strFile = strings.ReplaceAll(strFile, "\r\n", "\n") // 换行符用 \n 避免 win和 lnx执行时不一致
		/*/// Description: 订阅-行情应答
		  virtual void OnRspDepthMarketDataSubscribe(CHSRspInfoField *pRspInfo, int nRequestID, bool bIsLast) {};
		  virtual int Init(const char *pszLicFile,const char *pszSafeLevel = "", const char *pszPwd = "", const char *pszSslFile = "", const char *pszSslPwd = "") = 0;*/
		re := regexp.MustCompile(`\s+/// (.*)\n[^v]*virtual\s+(\w+)\s+(\w+)\(([^)]*)\)`) // 分解函数定义:注释,返回类型,函数名,参数字段四部分
		funs := re.FindAllStringSubmatch(strFile, -1)
		tplsOn := make([]*tplStruct, 0)
		tplsFn := make([]*tplStruct, 0)
		for _, fun := range funs {
			funComment, _, funName, funParams := fun[1], fun[2], fun[3], fun[4]
			funComment = strings.ReplaceAll(funComment, "Description:", "")
			re := regexp.MustCompile(`\s*((const)?\s*\w+)\s+([*]?[ ]?\w+)`) //参数分解:类型,名称
			fields := re.FindAllStringSubmatch(funParams, -1)
			funFields := make([]fieldStruct, 0)
			for _, field := range fields {
				funFields = append(funFields, fieldStruct{FieldType: field[1], FieldName: field[3]})
			}
			if strings.HasPrefix(funName, "On") { // On 响应函数
				tplsOn = append(tplsOn, &tplStruct{
					Comment:      funComment,
					FuncTypeName: funName[2:] + "Type",
					FuncName:     funName[2:],
					FuncFields:   funFields,
				})
			} else {
				tplsFn = append(tplsFn, &tplStruct{
					Comment:      funComment,
					FuncTypeName: funName + "Type",
					FuncName:     funName,
					FuncFields:   funFields,
				})
			}
		}
		tplExeFunc(title, tplsOn, tplsFn)
	}
}

func genPy() {
	generate(func(title string, on, fn []*tplStruct) {
		funcs := make(map[string]interface{})
		funcs["On"] = on
		funcs["Fn"] = fn
		fm := make(template.FuncMap)
		fm["baseType"] = func(preType string) string {
			if preType == "CHSMdSpi" {
				return "c_void_p"
			}
			if preType == "CHSTradeSpi" {
				return "c_void_p"
			}
			if preType == "int" { // SubscribeMarketData(char *ppInstrumentID[], int nCount)
				return "c_int32"
			}
			return "c_void_p" // char*  CThost结构体
		}
		fm["fnBaseType"] = func(fieldTypeName string) string {
			if fieldTypeName == "char" {
				return "str"
			}
			if fieldTypeName == "CHSMdSpi" {
				return "c_void_p"
			}
			if fieldTypeName == "CHSTradeSpi" {
				return "c_void_p"
			}
			return fieldTypeName
		}
		fm["evBaseType"] = func(fieldTypeName string) string {
			if strings.HasPrefix(fieldTypeName, "CHS") { // struct
				return fmt.Sprintf("POINTER(%s)", fieldTypeName)
			}
			if fieldTypeName == "int" {
				return "c_int32"
			}
			if fieldTypeName == "bool" {
				return "c_bool"
			}
			return fieldTypeName
		}
		fm["param"] = func(fieldType, fieldName string) string {
			if fieldName == "ppInstrumentID" { // 类型为 Array[c_char_p]
				return fieldName
			}
			if fieldType == "char" {
				return fmt.Sprintf("bytes(%s, encoding='ascii')", fieldName)
			}
			if fieldType == "CHSMdSpi" {
				return fieldName
			}
			if fieldType == "CHSTradeSpi" {
				return fieldName
			}
			if strings.HasPrefix(fieldType, "CHS") {
				return fmt.Sprintf("byref(%s)", fieldName)
			}
			return fieldName
		}
		fm["onParam"] = func(fieldType, fieldName string) string {
			if strings.HasPrefix(fieldType, "CHS") {
				// self.OnRspQryInvestorPosition(copy.deepcopy(POINTER(CHSInvestorPositionField).from_param(pInvestorPosition).contents) if pInvestorPosition else CHSInvestorPositionField(), copy.deepcopy(POINTER(CHSRspInfoField).from_param(pRspInfo).contents), nRequestID, bIsLast)
				return fmt.Sprintf("copy.deepcopy(POINTER(%s).from_param(%s).contents) if %s else %s()", fieldType, fieldName, fieldName, fieldType)
			}
			return fieldName
		}
		tmpl(title+"_ctp.py.tpl", funcs, fm, "../py")
	})
}

// genC quote.h quote.cpp trade.h trade.cpp
func genC() {
	generate(func(title string, tplsOn, tplsFn []*tplStruct) {
		tmpl(title+".h.tpl", tplsOn, nil, "../c")
		mpCpp := make(map[string]interface{})
		mpCpp["On"] = tplsOn
		mpCpp["Fn"] = tplsFn
		tmpl(title+".cpp.tpl", mpCpp, nil, "../c")
	})
}

// genGo quote.go trade.go
func genGo() {
	var gen = func(title string, tplsOn, tplsFn []*tplStruct) {
		for _, fn := range tplsFn { // 主调函数
			// 增加 void* api 首个参数
			tmp := []fieldStruct{{FieldType: "void*", FieldName: "api"}}
			tmp = append(tmp, fn.FuncFields...)
			fn.FuncFields = tmp
		}
		funcs := make(map[string]interface{})
		funcs["On"] = tplsOn
		funcs["Fn"] = tplsFn
		fm := make(template.FuncMap)
		fm["struct_Type"] = func(structType string) string {
			if structType == "CHSMdSpi" {
				return "void"
			}
			if structType == "CHSTradeSpi" {
				return "void"
			}
			if strings.HasPrefix(structType, "CHS") { // struct
				return "struct " + structType // struct CHSRspUserLoginField *pRspUserLogin
			}
			if structType == "bool" {
				return "_Bool"
			}
			if structType == "SUB_TERT_TYPE" { // C+ enum类型
				return "int"
			}
			return structType
		}
		fm["C_struct"] = func(structType string) string {
			if strings.HasPrefix(structType, "void*") {
				return "unsafe.Pointer" // aip | spi
			}
			if strings.HasPrefix(structType, "CHS") { // struct
				return "*C.struct_" + structType // field *C.struct_CHSRspUserLoginField
			}
			if structType == "int" {
				return "C.int"
			}
			if structType == "bool" {
				return "C._Bool"
			}
			return structType
		}
		fm["ctp_type"] = func(structType string) string {
			if strings.HasPrefix(structType, "CHS") { // struct
				return fmt.Sprintf("*def.%s", structType)
			}
			if strings.HasPrefix(structType, "void*") {
				return "unsafe.Pointer" // aip | spi
			}
			return structType
		}
		fm["ctp_param"] = func(structType, field string) string {
			if strings.HasPrefix(structType, "CHS") { // struct
				return fmt.Sprintf("(*def.%s)(unsafe.Pointer(%s))", structType, strings.TrimPrefix(field, "*"))
			}
			if structType == "int" {
				return "int(" + field + ")"
			}
			if structType == "bool" {
				return "bool(" + field + ")"
			}
			return field
		}
		tmpl(title+"_lnx.go.tpl", funcs, fm, "../go/lnx")
		tmpl(title+"_win.go.tpl", funcs, fm, "../go/win")
	}

	generate(gen)

	// generate(func(title string, tplsOn, tplsFn []*tplStruct) {
	// 	// for _, v := range [][]*tplStruct{tplsOn, tplsFn} {
	// 	for _, fn := range tplsFn { // 主调函数
	// 		// 增加 void* api 首个参数
	// 		tmp := []fieldStruct{{FieldType: "void*", FieldName: "api"}}
	// 		tmp = append(tmp, fn.FuncFields...)
	// 		fn.FuncFields = tmp
	// 	}
	// 	for _, fn := range tplsOn { // 响应函数
	// 		// 增加 void* spi 首个参数
	// 		tmp := []fieldStruct{{FieldType: "void*", FieldName: "spi"}}
	// 		tmp = append(tmp, fn.FuncFields...)
	// 		fn.FuncFields = tmp
	// 	}
	// 	// }
	// 	mpCpp := make(map[string]interface{})
	// 	mpCpp["On"] = tplsOn
	// 	mpCpp["Fn"] = tplsFn
	// 	fm := make(template.FuncMap)
	// 	fm["ctp_type"] = func(structType string) string {
	// 		if strings.HasPrefix(structType, "CHS") { // struct
	// 			return fmt.Sprintf("*ctp.%s", structType) // *ctp.CHSUserLogoutField
	// 		}
	// 		return structType
	// 	}
	// 	tmpl(title+"_win.go.tpl", mpCpp, fm, "../go/win")
	// })
}

func genCs() {
	generate(func(title string, tplsOn, tplsFn []*tplStruct) {
		// for _, fn := range tplsFn { // 主调函数
		// 	// 增加 void* api 首个参数
		// 	tmp := []fieldStruct{{FieldType: "IntPtr", FieldName: "api"}}
		// 	tmp = append(tmp, fn.FuncFields...)
		// 	fn.FuncFields = tmp
		// }
		funcs := make(map[string]interface{})
		funcs["On"] = tplsOn
		funcs["Fn"] = tplsFn
		fm := make(template.FuncMap)
		fm["fndele"] = func(structType string) string { // 用 IntPtr 作为 struct 类型
			if strings.HasPrefix(structType, "CHS") { // 有可能为 null，故用 IntPtr
				return "IntPtr " // struct CHSRspUserLoginField *pRspUserLogin
			}
			if structType == "THOST_TE_RESUME_TYPE" {
				return "int"
			}
			if structType == "char" {
				return "string"
			}
			return structType
		}
		fm["fieldType"] = func(structType string) string {
			if structType == "CHSMdSpi" {
				return "IntPtr"
			}
			if structType == "CHSTradeSpi" {
				return "IntPtr"
			}
			if strings.HasPrefix(structType, "CHS") { // 有可能为 null，故用 IntPtr
				return structType // struct CHSRspUserLoginField *pRspUserLogin
			}
			if structType == "THOST_TE_RESUME_TYPE" {
				return "int"
			}
			if structType == "char" {
				return "string"
			}
			return structType
		}
		fm["refFieldType"] = func(structType string) string {
			if structType == "CHSMdSpi" {
				return "IntPtr"
			}
			if structType == "CHSTradeSpi" {
				return "IntPtr"
			}
			if strings.HasPrefix(structType, "CHS") { // 有可能为 null，故用 IntPtr
				return "ref " + structType // struct CHSRspUserLoginField *pRspUserLogin
			}
			if structType == "THOST_TE_RESUME_TYPE" {
				return "int"
			}
			if structType == "char" {
				return "string"
			}
			return structType
		}
		fm["leftOne"] = func(str string) string {
			return str[0:1]
		}
		fm["param"] = func(fieldType, field string) string {
			if fieldType == "CHSMdSpi" {
				return field
			}
			if fieldType == "CHSTradeSpi" {
				return field
			}
			if strings.HasPrefix(fieldType, "CHS") { // struct
				return "ref " + field
			}
			return field
		}
		tmpl(title+"_ctp.cs.tpl", funcs, fm, "../c#/win")
		tmpl(title+"_ctp.cs.tpl", funcs, fm, "../c#/lnx")
		// 替换 .dll 为 .so
		bs, _ := ioutil.ReadFile("../c#/lnx/" + title + "_ctp.cs")
		bs = bytes.ReplaceAll(bs, []byte(".dll"), []byte(".so"))
		ioutil.WriteFile("../c#/lnx/"+title+"_ctp.cs", bs, os.ModePerm)
	})
}

// generateStruct
func generateStruct(fn func([]*tplStruct)) {
	bsFile, err := os.ReadFile(srcPath + "HSStruct.h")
	if err != nil {
		panic(err)

	}
	strFile := string(bsFile)
	strFile = strings.ReplaceAll(strings.ReplaceAll(strFile, "\r\n", "\n"), "\n\t", "\n")
	// 汉字处理
	// bsFile, _ = simplifiedchinese.GB18030.NewDecoder().Bytes(bsFile)

	re := regexp.MustCompile(`///\s*(.*)\n\s*struct\s*(\w*)\s*([^}]*)}`) // 分成struct的注释,名称,字段两部分
	structs := re.FindAllStringSubmatch(string(strFile), -1)
	tss := make([]*tplStruct, 0)
	for _, strc := range structs {
		ts := &tplStruct{
			Comment:      strc[1],
			FuncTypeName: strc[2],
		}
		re = regexp.MustCompile(`(///([^\r\n]*)\s*)?(\w+)\s+([^;]+);`) // 所有字段再分解成各个单独字段: 注释(可能含空格),类型,名称
		fields := re.FindAllStringSubmatch(strc[3], -1)
		for _, v := range fields {
			ts.FuncFields = append(ts.FuncFields, fieldStruct{
				Comment:   v[2],
				FieldType: v[3],
				FieldName: v[4],
			})
		}
		tss = append(tss, ts)
	}
	fn(tss)
}

// genPyStruct
func genPyStruct() {
	bs, _ := ioutil.ReadFile("../py/datatype.py")
	dt := string(bs)
	generateStruct(func(ts []*tplStruct) {
		fm := make(template.FuncMap)
		fm["baseType"] = func(fieldType string) string {
			if strings.Contains(dt, fieldType+"(Enum)") { // enum
				return "c_char"
			}
			return fieldType
		}
		fm["rtn"] = func(fieldType, fieldName string) string {
			if strings.Contains(fieldType, "CombOffsetFlag") { // 特别处理
				return fmt.Sprintf("TThostFtdcOffsetFlagType(ord(self.%s))", fieldName)
			}
			if strings.Contains(fieldType, "CombHedgeFlag") { // 特别处理
				return fmt.Sprintf("TThostFtdcHedgeFlagType(ord(self.%s))", fieldName)
			}
			if strings.Contains(dt, fieldType+" = c_char*") { //  TThostFtdcProductInfoType = c_char*11
				return fmt.Sprintf("str(self.%s, 'GBK')", fieldName)
			}
			// TThostFtdcDirectionType(ord(f.getOffsetFlag()))
			if strings.Contains(dt, fieldType+"(Enum)") { // enum
				return fmt.Sprintf("%s(ord(self.%s))", fieldType, fieldName)
			}
			return "self." + fieldName
		}
		tmpl("struct.py.tpl", ts, fm, "../py")
	})
}

// genGoStruct
func genGoStruct() {
	generateStruct(func(ts []*tplStruct) {
		tmpl("struct.go.tpl", ts, nil, "../go/def")
	})
}

// genCsStruct
func genCsStruct() {
	bs, _ := ioutil.ReadFile("../c#/win/datatype.cs")
	lines := strings.Split(strings.ReplaceAll(string(bs), "\r\n", "\n"), "\n")
	strLen := make(map[string]int)
	baseType := make(map[string]string)
	for _, v := range lines {
		// using TThostFtdcSystemIDType = System.String; // 21;
		if strings.Contains(v, "System.String;") {
			fs := strings.Split(v, " = System.String; // ")
			strLen[strings.Split(fs[0], " ")[1]], _ = strconv.Atoi(strings.Split(fs[1], ";")[0])
		}
		if strings.Contains(v, "using") {
			fs := strings.Split(strings.ReplaceAll(v, "using ", ""), "=")
			baseType[strings.TrimSpace(fs[0])] = strings.TrimSpace(strings.Split(fs[1], ";")[0])
		}
	}
	generateStruct(func(ts []*tplStruct) {
		fm := make(template.FuncMap)
		fm["charLen"] = func(fieldType string) int {
			if len, ok := strLen[fieldType]; ok { // string
				return len
			}
			return 0
		}
		fm["baseType"] = func(fieldType string) string {
			if t, ok := baseType[fieldType]; ok {
				return t
			}
			return fieldType
		}
		tmpl("struct.cs.tpl", ts, fm, "../c#/win")
		tmpl("struct.cs.tpl", ts, fm, "../c#/lnx")
	})
}

// generateDataType
func generateDataType(fn func([]dataType)) {
	bsFile, err := os.ReadFile(srcPath + "HSDataType.h")
	if err != nil {
		panic(err)
	}
	// 汉字处理
	// bsFile, _ = simplifiedchinese.GB18030.NewDecoder().Bytes(bsFile)
	strFile := string(bsFile)
	strFile = strings.ReplaceAll(strings.ReplaceAll(strFile, "\r\n", "\n"), "\n\t", "\n")
	// 替换全角字符
	strFile = strings.ReplaceAll(strFile, "（", "(")
	strFile = strings.ReplaceAll(strFile, "）", ")")
	strFile = strings.ReplaceAll(strFile, "：", ":")
	/*//////////////////////////////////////////////////////////////////////////
	/// HSExerciseType：期权行权类型
	//////////////////////////////////////////////////////////////////////////
	/// 放弃
	#define HS_ET_Abandon '0'
	/// 执行
	#define HS_ET_Exec    '1'
	typedef char HSExerciseType;
	*/
	re := regexp.MustCompile(`///\s+HS.+:\s?(.*)\n/+([^;]*)`) // 注释,全部定义
	defs := re.FindAllStringSubmatch(strFile, -1)
	tss := make([]dataType, 0)
	for _, v := range defs {
		sub := v[2] // 值定义 & 类型名
		fmt.Println(sub)
		subDef := regexp.MustCompile(`typedef\s+(\w+)\s+(HS.+)`).FindStringSubmatch(sub) // typedef int32|char HSDate[256] ;
		ts := dataType{
			Comment: v[1],
			Type:    subDef[1], // 基础类型
			Name:    subDef[2],
		}
		// define HS_OD_CollateralOut 36 '1'
		reSub := regexp.MustCompile(`///\s+(.*)\s*\n#define\s+(HS\w*)\s+([\w|']+)`) // 注释,名称,值(34 or '1')
		subs := reSub.FindAllStringSubmatch(sub, -1)
		if len(subs) > 0 { // enum 类型定义
			for _, v := range subs {
				ts.Subs = append(ts.Subs, dataTypeValue{
					Comment: v[1],
					Name:    v[2],
					Value:   v[3],
				})
			}
		} else {
			if strings.Contains(ts.Name, "[") { // typedef char HSMsgContent[256];
				ts.Type = "[" + strings.Split(ts.Name, "[")[1] + "byte"
				ts.Name = strings.Split(ts.Name, "[")[0]
			}
		}
		tss = append(tss, ts)
	}
	/*//////////////////////////////////////////////////////////////////////////
	/// HSInstrumentName：合约名字
	//////////////////////////////////////////////////////////////////////////
	typedef char HSInstrumentName[32];*/
	// re = regexp.MustCompile(`typedef\s+(\w+)\s+(.+)\s*;`) // 注释,类型,自定义类型
	// defs = re.FindAllStringSubmatch(strFile, -1)
	// for _, v := range defs {
	// 	ts := &tplStruct{
	// 		Comment:      v[1],
	// 		FuncTypeName: v[2], // 基础类型
	// 		FuncName:     v[3],
	// 	}
	// 	// typedef char TThostFtdcTraderIDType[21]; -> type TThostFtdcTraderIDType [21]byte
	// 	if strings.Contains(ts.FuncName, "[") {
	// 		ts.FuncTypeName = "[" + strings.Split(ts.FuncName, "[")[1] + "byte"
	// 		ts.FuncName = strings.Split(ts.FuncName, "[")[0]
	// 	}
	// 	tss = append(tss, ts)
	// }
	fn(tss)
}

func genPyDataType() {
	generateDataType(func(ts []dataType) {
		fm := make(template.FuncMap)
		fm["baseType"] = func(preType string) string {
			if preType == "int" { // typedef int TThostFtdcIPPortType; -> TThostFtdcIPPortType = c_int32
				return "c_int32"
			}
			if preType == "double" { // typedef double TThostFtdcPriceType; -> TThostFtdcPriceType = c_double
				return "c_double"
			}
			if preType == "short" { // typedef short TThostFtdcSequenceSeriesType; -> TThostFtdcSequenceSeriesType = c_short
				return "c_short"
			}
			if preType == "char" { // typedef char TThostFtdcNewsUrgencyType;
				return "c_char"
			}
			// [nn]byte
			if strings.Contains(preType, "[") { // typedef char TThostFtdcTraderIDType[21]; -> TThostFtdcTraderIDType = c_char*21
				return "c_char*" + strings.Split(strings.Split(preType, "[")[1], "]")[0]
			}
			return preType
		}
		fm["atoi"] = func(char string) int {
			return int(char[0])
		}
		tmpl("datatype.py.tpl", ts, fm, "../py")
	})
}

func genGoDataType() {
	generateDataType(func(ts []dataType) {
		fm := make(template.FuncMap)
		fm["baseType"] = func(preType string) string {
			if preType == "int" { // typedef int TThostFtdcIPPortType; -> type TThostFtdcIPPortType int32
				return "int32"
			}
			if preType == "double" { // typedef double TThostFtdcPriceType; -> type TThostFtdcPriceType float64
				return "float64"
			}
			if preType == "short" { // typedef short TThostFtdcSequenceSeriesType; -> type TThostFtdcSequenceSeriesType int16
				return "int16"
			}
			if preType == "char" {
				return "byte"
			}
			return preType
		}
		tmpl("datatype.go.tpl", ts, fm, "../go/def")
	})
}

// genCsDataType
func genCsDataType() {
	generateDataType(func(ts []dataType) {
		fm := make(template.FuncMap)
		fm["baseType"] = func(preType string) string {
			if preType == "int" { // typedef int TThostFtdcIPPortType;
				return "System.Int32"
			}
			if preType == "double" { // typedef double TThostFtdcPriceType;
				return "System.Double"
			}
			if preType == "short" { // typedef short TThostFtdcSequenceSeriesType;
				return "System.Int16"
			}
			if preType == "bool" { // typedef short TThostFtdcSequenceSeriesType;
				return "System.Bool"
			}
			if preType == "char" { // typedef char TThostFtdcNewsUrgencyType;
				return "System.Char"
			}
			// [nn]byte
			if strings.Contains(preType, "[") { // typedef char TThostFtdcTraderIDType[21]; -> TThostFtdcTraderIDType = c_char*21
				return "System.String; // " + strings.Split(strings.Split(preType, "[")[1], "]")[0]
			}
			return preType
		}
		tmpl("datatype.cs.tpl", ts, fm, "../c#/win")
		tmpl("datatype.cs.tpl", ts, fm, "../c#/lnx")
	})
}
